"""
策略引擎服务
"""
import asyncio
import json
import logging
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, asdict

from ..core.config import settings
from ..core.database import db_manager
from ..strategies.base import BaseStrategy
from ..strategies.moving_average import MovingAverageCrossStrategy
from ..strategies.volatility_breakout import VolatilityBreakoutStrategy

logger = logging.getLogger(__name__)


@dataclass
class StrategyStatus:
    """策略状态"""
    strategy_id: str
    name: str
    strategy_type: str
    is_active: bool
    parameters: Dict[str, Any]
    last_run_time: Optional[datetime] = None
    total_trades: int = 0
    total_pnl: float = 0.0
    win_rate: float = 0.0
    max_drawdown: float = 0.0
    status: str = "stopped"  # stopped/running/error


class StrategyEngine:
    """策略引擎"""
    
    def __init__(self):
        self.strategies: Dict[str, BaseStrategy] = {}
        self.strategy_status: Dict[str, StrategyStatus] = {}
        self.is_running = False
        self.update_task: Optional[asyncio.Task] = None
        self._lock = asyncio.Lock()
        
        # 注册策略类型
        self.strategy_types = {
            "moving_average": MovingAverageCrossStrategy,
            "volatility_breakout": VolatilityBreakoutStrategy
        }
    
    async def start(self):
        """启动策略引擎"""
        try:
            logger.info("正在启动策略引擎...")
            
            # 从数据库加载策略
            await self._load_strategies_from_db()
            
            # 启动更新任务
            self.is_running = True
            self.update_task = asyncio.create_task(self._update_loop())
            
            logger.info("策略引擎启动完成")
            
        except Exception as e:
            logger.error(f"策略引擎启动失败: {e}")
            raise
    
    async def stop(self):
        """停止策略引擎"""
        try:
            logger.info("正在停止策略引擎...")
            
            self.is_running = False
            
            # 停止所有策略
            for strategy_id in list(self.strategies.keys()):
                await self.stop_strategy(strategy_id)
            
            # 等待更新任务结束
            if self.update_task:
                self.update_task.cancel()
                try:
                    await self.update_task
                except asyncio.CancelledError:
                    pass
            
            logger.info("策略引擎已停止")
            
        except Exception as e:
            logger.error(f"策略引擎停止失败: {e}")
    
    async def _load_strategies_from_db(self):
        """从数据库加载策略"""
        try:
            strategies = await db_manager.get_all_strategies()
            
            for strategy_data in strategies:
                strategy_id = strategy_data["strategy_id"]
                strategy_type = strategy_data["strategy_type"]
                
                # 创建策略实例
                if strategy_type in self.strategy_types:
                    strategy_class = self.strategy_types[strategy_type]
                    strategy = strategy_class(strategy_id, strategy_data["parameters"])
                    
                    self.strategies[strategy_id] = strategy
                    self.strategy_status[strategy_id] = StrategyStatus(
                        strategy_id=strategy_id,
                        name=strategy_data["name"],
                        strategy_type=strategy_type,
                        is_active=strategy_data["is_active"],
                        parameters=strategy_data["parameters"]
                    )
                    
                    logger.info(f"策略 {strategy_id} 加载完成")
                else:
                    logger.warning(f"未知的策略类型: {strategy_type}")
                    
        except Exception as e:
            logger.error(f"从数据库加载策略失败: {e}")
    
    async def _update_loop(self):
        """更新循环"""
        try:
            while self.is_running:
                try:
                    # 更新所有活跃策略
                    await self._update_strategies()
                    
                    # 等待下次更新
                    await asyncio.sleep(settings.STRATEGY_UPDATE_INTERVAL)
                    
                except asyncio.CancelledError:
                    break
                except Exception as e:
                    logger.error(f"策略更新循环错误: {e}")
                    await asyncio.sleep(5)  # 出错后等待5秒
                    
        except Exception as e:
            logger.error(f"策略更新循环异常: {e}")
    
    async def _update_strategies(self):
        """更新策略"""
        try:
            current_time = datetime.now()
            
            for strategy_id, strategy in self.strategies.items():
                status = self.strategy_status[strategy_id]
                
                if not status.is_active:
                    continue
                
                try:
                    # 更新策略
                    await strategy.update(current_time)
                    
                    # 更新状态
                    status.last_run_time = current_time
                    status.total_trades = strategy.total_trades
                    status.total_pnl = strategy.total_pnl
                    status.win_rate = strategy.win_rate
                    status.max_drawdown = strategy.max_drawdown
                    
                    # 检查是否有新的交易信号
                    signals = await strategy.get_signals()
                    if signals:
                        for signal in signals:
                            await self._process_trade_signal(strategy_id, signal)
                    
                except Exception as e:
                    logger.error(f"策略 {strategy_id} 更新失败: {e}")
                    status.status = "error"
        
        except Exception as e:
            logger.error(f"更新策略失败: {e}")
    
    async def _process_trade_signal(self, strategy_id: str, signal: Dict):
        """处理交易信号"""
        try:
            logger.info(f"策略 {strategy_id} 生成交易信号: {signal}")
            
            # 这里可以广播信号给前端
            # await broadcast_trade_signal(strategy_id, signal)
            
            # 或者直接调用交易引擎
            # await trade_engine.execute_signal(strategy_id, signal)
            
        except Exception as e:
            logger.error(f"处理交易信号失败: {e}")
    
    async def add_strategy(self, strategy_data: Dict) -> bool:
        """添加策略"""
        try:
            strategy_id = strategy_data["strategy_id"]
            strategy_type = strategy_data["strategy_type"]
            
            if strategy_id in self.strategies:
                logger.warning(f"策略 {strategy_id} 已存在")
                return False
            
            # 创建策略实例
            if strategy_type not in self.strategy_types:
                logger.error(f"未知的策略类型: {strategy_type}")
                return False
            
            strategy_class = self.strategy_types[strategy_type]
            strategy = strategy_class(strategy_id, strategy_data["parameters"])
            
            # 添加到引擎
            async with self._lock:
                self.strategies[strategy_id] = strategy
                self.strategy_status[strategy_id] = StrategyStatus(
                    strategy_id=strategy_id,
                    name=strategy_data["name"],
                    strategy_type=strategy_type,
                    is_active=False,
                    parameters=strategy_data["parameters"]
                )
            
            # 保存到数据库
            await db_manager.save_strategy(strategy_data)
            
            logger.info(f"策略 {strategy_id} 添加成功")
            return True
            
        except Exception as e:
            logger.error(f"添加策略失败: {e}")
            return False
    
    async def remove_strategy(self, strategy_id: str) -> bool:
        """移除策略"""
        try:
            if strategy_id not in self.strategies:
                logger.warning(f"策略 {strategy_id} 不存在")
                return False
            
            # 停止策略
            await self.stop_strategy(strategy_id)
            
            # 从引擎移除
            async with self._lock:
                if strategy_id in self.strategies:
                    del self.strategies[strategy_id]
                if strategy_id in self.strategy_status:
                    del self.strategy_status[strategy_id]
            
            logger.info(f"策略 {strategy_id} 移除成功")
            return True
            
        except Exception as e:
            logger.error(f"移除策略失败: {e}")
            return False
    
    async def start_strategy(self, strategy_id: str) -> bool:
        """启动策略"""
        try:
            if strategy_id not in self.strategies:
                logger.error(f"策略 {strategy_id} 不存在")
                return False
            
            status = self.strategy_status[strategy_id]
            if status.is_active:
                logger.warning(f"策略 {strategy_id} 已在运行")
                return False
            
            # 启动策略
            strategy = self.strategies[strategy_id]
            if await strategy.start():
                status.is_active = True
                status.status = "running"
                
                # 更新数据库
                strategy_data = await db_manager.get_strategy(strategy_id)
                if strategy_data:
                    strategy_data["is_active"] = True
                    await db_manager.save_strategy(strategy_data)
                
                logger.info(f"策略 {strategy_id} 启动成功")
                return True
            else:
                logger.error(f"策略 {strategy_id} 启动失败")
                return False
                
        except Exception as e:
            logger.error(f"启动策略失败: {e}")
            return False
    
    async def stop_strategy(self, strategy_id: str) -> bool:
        """停止策略"""
        try:
            if strategy_id not in self.strategies:
                logger.error(f"策略 {strategy_id} 不存在")
                return False
            
            status = self.strategy_status[strategy_id]
            if not status.is_active:
                logger.warning(f"策略 {strategy_id} 未运行")
                return True
            
            # 停止策略
            strategy = self.strategies[strategy_id]
            if await strategy.stop():
                status.is_active = False
                status.status = "stopped"
                
                # 更新数据库
                strategy_data = await db_manager.get_strategy(strategy_id)
                if strategy_data:
                    strategy_data["is_active"] = False
                    await db_manager.save_strategy(strategy_data)
                
                logger.info(f"策略 {strategy_id} 停止成功")
                return True
            else:
                logger.error(f"策略 {strategy_id} 停止失败")
                return False
                
        except Exception as e:
            logger.error(f"停止策略失败: {e}")
            return False
    
    def get_strategies(self) -> List[Dict]:
        """获取所有策略"""
        try:
            strategies = []
            
            for strategy_id, status in self.strategy_status.items():
                strategies.append({
                    "strategy_id": strategy_id,
                    "name": status.name,
                    "strategy_type": status.strategy_type,
                    "is_active": status.is_active,
                    "parameters": status.parameters,
                    "last_run_time": status.last_run_time.isoformat() if status.last_run_time else None,
                    "total_trades": status.total_trades,
                    "total_pnl": status.total_pnl,
                    "win_rate": status.win_rate,
                    "max_drawdown": status.max_drawdown,
                    "status": status.status
                })
            
            return strategies
            
        except Exception as e:
            logger.error(f"获取策略列表失败: {e}")
            return []
    
    def get_strategy(self, strategy_id: str) -> Optional[Dict]:
        """获取指定策略"""
        try:
            if strategy_id not in self.strategy_status:
                return None
            
            status = self.strategy_status[strategy_id]
            return {
                "strategy_id": strategy_id,
                "name": status.name,
                "strategy_type": status.strategy_type,
                "is_active": status.is_active,
                "parameters": status.parameters,
                "last_run_time": status.last_run_time.isoformat() if status.last_run_time else None,
                "total_trades": status.total_trades,
                "total_pnl": status.total_pnl,
                "win_rate": status.win_rate,
                "max_drawdown": status.max_drawdown,
                "status": status.status
            }
            
        except Exception as e:
            logger.error(f"获取策略失败: {e}")
            return None
    
    async def update_strategy_parameters(self, strategy_id: str, parameters: Dict) -> bool:
        """更新策略参数"""
        try:
            if strategy_id not in self.strategies:
                logger.error(f"策略 {strategy_id} 不存在")
                return False
            
            # 更新策略实例
            strategy = self.strategies[strategy_id]
            await strategy.update_parameters(parameters)
            
            # 更新状态
            status = self.strategy_status[strategy_id]
            status.parameters = parameters
            
            # 更新数据库
            strategy_data = await db_manager.get_strategy(strategy_id)
            if strategy_data:
                strategy_data["parameters"] = parameters
                await db_manager.save_strategy(strategy_data)
            
            logger.info(f"策略 {strategy_id} 参数更新成功")
            return True
            
        except Exception as e:
            logger.error(f"更新策略参数失败: {e}")
            return False


# 全局策略引擎实例
strategy_engine = StrategyEngine()
